package own.stu.jobgib.playown.io.channel;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;

public class Server {
    /**
     * ../new-step/oth-base/io/LINUX内核研究----IO复用函数epoll内核源代码深度剖析.md
     * ../new-step/oth-base/io/深度解析Java NIO底层实现原理（selector是怎样select的）.md
     *
     *  Linux TCP/IP协议栈之Socket的实现分析(Accept 接受一个连接) (https://blog.51cto.com/u_16081664/6229417)
     *
     *   Linux 查看tcp连接状态
     *      查看80端口连接数
     *      netstat -ant|grep -i "80"|wc -l
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {
//        blockIO();

        nonBlockIO();
    }

    private static void nonBlockIO() throws IOException {
        //ServerSocket serverSocket = new ServerSocket(8888);
        Selector selector = Selector.open();

        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.socket().bind(new InetSocketAddress(8888));
        serverSocketChannel.configureBlocking(false);

        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        //创建buffer
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

        while (true) {
            int count = selector.select();
            if (count == 0) {
                continue;
            }

            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                if (key.isAcceptable()) {
                    //获取到连接
                    SocketChannel accept = serverSocketChannel.accept();
                    //切换非阻塞模式
                    accept.configureBlocking(false);
                    //注册
                    accept.register(selector, SelectionKey.OP_READ);
                } else if (key.isReadable()) {
                    SocketChannel channel = (SocketChannel) key.channel();
                    //读取数据
                    int length = 0;
                    while ((length = channel.read(byteBuffer)) > 0) {
                        byteBuffer.flip();
                        System.out.println(new String(byteBuffer.array(), 0, length));
                        byteBuffer.clear();
                    }
                    channel.register(selector, SelectionKey.OP_WRITE);
                } else if (key.isWritable()) {
                    SocketChannel channel = (SocketChannel) key.channel();
                    byteBuffer.put("ni hao \n".getBytes());
                    byteBuffer.flip();
                    channel.write(byteBuffer);
                    byteBuffer.clear();
                    channel.register(selector, SelectionKey.OP_READ);
                }

                iterator.remove();
            }

        }

    }

    private static void blockIO() throws IOException {

        ServerSocket serverSocket = new ServerSocket(8888);
        doInfo();

        while (true) {
            Socket accept = serverSocket.accept();

            dealInfo(accept);
        }
    }


    static BlockingDeque<Socket> socketList = new LinkedBlockingDeque<>();

    static void dealInfo(Socket socket) {
        socketList.add(socket);
    }

    static void doInfo() {

        Runnable run = () -> {

            try {
                Socket socket = null;
                while ((socket = socketList.take()) != null) {
                    InputStream inputStream = socket.getInputStream();
                    byte[] bytes = new byte[8];
                    while (inputStream.read(bytes) != -1) { // TODO
                        System.out.print(new String(bytes));
                    }
                    System.out.println();
                    OutputStream outputStream = socket.getOutputStream();
                    outputStream.write("ni hao".getBytes());
                    outputStream.flush();
                }

            } catch (Exception e) {
            }
        };

        for (int i = 0; i < 5; i++)
            new Thread(run, "t - " + i).start();
    }


}
